/*
 * This file is part of the MicroPython project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013-2018 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "shared/runtime/interrupt_char.h"
#include "shared/runtime/mpirq.h"

#include "machine.h"
#include "mpconfigport.h"


// w806的手册号称串口可以达到2M波特率, 我这里配置950K没问题, >=980K波特率就不行了,可能是杜邦线连接的原因
// 串口部分移植完成

// 完成串口和编号映射, mask数组表示串口是否有效
static USART_TypeDef* const usart_map[] = {UART0, UART1, UART2, UART3, UART4, UART5};

// 检查串口是否被配置(被硬件支持)
static bool const usart_valid_mask[] = {
#if MICROPY_HW_EN_UART0
    true,
#else
	false,
#endif
#if MICROPY_HW_EN_UART1
    true,
#else
    false,
#endif
#if MICROPY_HW_EN_UART2
    true,
#else
    false,
#endif
#if MICROPY_HW_EN_UART3
    true,
#else
    false,
#endif
#if MICROPY_HW_EN_UART4
    true,
#else
    false,
#endif
#if MICROPY_HW_EN_UART5
    true,
#else
    false,
#endif
};

// 根据编号获取串口控制结构
USART_TypeDef* _get_uart_by_id(int nr)
{
	if(nr > sizeof(usart_map) / sizeof(usart_map[0]))
		mp_raise_ValueError(MP_ERROR_TEXT("uart id should be 0 ~ 5"));
	else
		return usart_map[nr];
	return NULL;
}


// 计算当前串口波特率baud_act=freq/(16*udiv.ubdiv_frac), ubdiv_frac放大了16倍转换成整数
int _get_act_baudrate(pyb_uart_obj_t* self)
{
	wm_sys_clk sysclk;
    SystemClock_Get(&sysclk);
    
    //printf("CLK_DIV:%x, cpuclk:%d, apbclk:%d, wlanclk:%d.\n", RCC->CLK_DIV, sysclk.cpuclk, sysclk.apbclk, sysclk.wlanclk);
    
	int baudr = self->huart.Instance->BAUDR;
	int ubdiv = baudr & 0xFFFF;       // 低16位存储分频结果的整数部分
	int ubdiv_frac = baudr >> 16;     // 高4位保存分频结果的小数部分(乘以16放大)
	return (sysclk.apbclk * 1000000) / 16 * 10 / ((ubdiv+1)*10+ubdiv_frac*10/16);  // 分子分母放大10倍(小数位放大10倍,参与计算)
}

// 判断串口是否存在
bool _is_uart_exists(int uart_id)
{
	if(0 <= uart_id && uart_id <=5){
		return usart_valid_mask[uart_id];
	}
	return false;
	
}

/// \moduleref pyb
/// \class UART - duplex serial communication bus
///
/// UART implements the standard UART/USART duplex serial communications protocol.  At
/// the physical level it consists of 2 lines: RX and TX.  The unit of communication
/// is a character (not to be confused with a string character) which can be 8 or 9
/// bits wide.
///
/// UART objects can be created and initialised using:
///
///     from pyb import UART
///
///     uart = UART(1, 9600)                         # init with given baudrate
///     uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
///
/// Bits can be 8 or 9.  Parity can be None, 0 (even) or 1 (odd).  Stop can be 1 or 2.
///
/// A UART object acts like a stream object and reading and writing is done
/// using the standard stream methods:
///
///     uart.read(10)       # read 10 characters, returns a bytes object
///     uart.read()         # read all available characters
///     uart.readline()     # read a line
///     uart.readinto(buf)  # read and store into the given buffer
///     uart.write('abc')   # write the 3 characters
///
/// Individual characters can be read/written using:
///
///     uart.readchar()     # read 1 character and returns it as an integer
///     uart.writechar(42)  # write 1 character
///
/// To check if there is anything to be read, use:
///
///     uart.any()               # returns True if any characters waiting
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
    if (!self->is_enabled) {
            mp_printf(print, "UART(%u)", self->uart_id);
    } else {
        uint8_t databits = 8;  // UART_WORDLENGTH_5B, UART_WORDLENGTH_6B, UART_WORDLENGTH_7B, UART_WORDLENGTH_8B
		// 数据位判断
        switch(self->huart.Init.WordLength){
        case UART_WORDLENGTH_5B:
            databits = 5;
            break;
        case UART_WORDLENGTH_6B:
            databits = 6;
            break;
        case UART_WORDLENGTH_7B:
            databits = 7;
            break;
        case UART_WORDLENGTH_8B:
            databits = 8;
            break;
        } 
        mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=", self->uart_id, self->huart.Init.BaudRate, databits);
		
        // 校验位判断
        if (self->huart.Init.Parity & UART_PARITY_ODD) {
            mp_print_str(print, "odd");
        } else if (self->huart.Init.Parity & UART_PARITY_EVEN) {
            mp_print_str(print, "even");
        } else {
            mp_print_str(print, "none");
        }

		// 停止位判断
        mp_printf(print, ", stop=%u, flow=", (self->huart.Init.StopBits == UART_STOPBITS_1) ? (1) : (2)); // stopbit=1 or2
        // 流控判断, 默认不开CTS、RTS
        mp_print_str(print, "none");
        // 输出其他信息
        mp_printf(print, ", timeout=%u, rxbuf=%u",
            self->timeout, self->fifo.buf_len == 0 ? 0 : self->fifo.buf_len - 1); // -1 to adjust for usable length of buffer
        mp_print_str(print, ")");
    }
}


/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, flow=0, read_buf_len=64)
///
/// Initialise the UART bus with the given parameters:
///
///   - `baudrate` is the clock rate.
///   - `bits` is the number of bits per byte, 7, 8 or 9.
///   - `parity` is the parity, `None`, 0 (even) or 1 (odd).
///   - `stop` is the number of stop bits, 1 or 2.
///   - `timeout` is the timeout in milliseconds to wait for the first character.
///   - `flow` is RTS | CTS where RTS == 256, CTS == 512
///   - `read_buf_len` is the character length of the read buffer (0 to disable).
STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 115200} },
        { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
        { MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
        { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },
        { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} },
        { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
        { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 128} },
        { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 128} }, // legacy
    };

    // 如果已初始化, 则重新初始化
    if(self->is_enabled){
		HAL_UART_DeInit(&self->huart);
        HAL_Delay(30);
    }
    // parse args
    struct {
        mp_arg_val_t baudrate, bits, parity, stop, flow, timeout, rxbuf, read_buf_len;
    } args;
    mp_arg_parse_all(n_args, pos_args, kw_args,
        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);

    // baudrate
    uint32_t baudrate = args.baudrate.u_int;

    // parity
    uint32_t bits = args.bits.u_int;
    uint32_t parity;
    if (args.parity.u_obj == mp_const_none) {
        parity = UART_PARITY_NONE;
    } else {
        mp_int_t p = mp_obj_get_int(args.parity.u_obj);
        parity = (p & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN;
    }

    // number of bits
    if (bits == 8) {
        bits = UART_WORDLENGTH_8B;
    } else if (bits == 7) {
        bits = UART_WORDLENGTH_7B;
    } else if (bits == 6) {
        bits = UART_WORDLENGTH_6B;
	} else if(bits == 5){
		bits = UART_WORDLENGTH_5B;
    } else {
        mp_raise_ValueError(MP_ERROR_TEXT("unsupported combination of bits and parity"));
    }

    // stop bits
    uint32_t stop;
    switch (args.stop.u_int) {
        case 1:
            stop = UART_STOPBITS_1;
            break;
        default:
            stop = UART_STOPBITS_2;
            break;
    }

    // flow control
    uint32_t flow = args.flow.u_int;

    // Save attach_to_repl setting because uart_init will disable it.
    //bool attach_to_repl = self->attached_to_repl;

    // init UART (if it fails, it's because the port doesn't exist)
	self->huart.Instance = _get_uart_by_id(self-> uart_id);
	self->huart.Init.BaudRate = baudrate;
	self->huart.Init.WordLength = bits;
	self->huart.Init.StopBits = stop;
	self->huart.Init.Parity = parity;
	self->huart.Init.Mode = UART_MODE_TX | UART_MODE_RX;
	self->huart.Init.HwFlowCtl = flow;
	if (HAL_UART_Init(&self->huart) != HAL_OK){
    //if (!uart_init(self, baudrate, bits, parity, stop, flow)) {
        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) doesn't exist"), self->uart_id);
    }

    // set timeout
    self->timeout = args.timeout.u_int;


	// setup the read buffer
	if(self->fifo.buf){
	    m_del(byte, self->fifo.buf, self->fifo.buf_len);
    }
	if (args.rxbuf.u_int >= 0) {
		// rxbuf overrides legacy read_buf_len
		args.read_buf_len.u_int = args.rxbuf.u_int;
	}

	// read buffer using interrupts
	size_t len = ((args.read_buf_len.u_int >= UART_FIFO_FULL) ? (args.read_buf_len.u_int) : (UART_FIFO_FULL)) + 1; // 保证buffer足够大
	//uint8_t *buf = m_new(byte, len * sizeof(uint8_t));
	self->fifo.buf = m_new(byte, len);
	self->fifo.buf_len = len;    // 设置缓存长度
	self->fifo.front = 0;        // 队头
	self->fifo.rear = 0;         // 队尾
	
    // compute actual baudrate that was configured
    uint32_t actual_baudrate = _get_act_baudrate(self);

    // check we could set the baudrate within 5%
    uint32_t baudrate_diff;
    if (actual_baudrate > baudrate) {
        baudrate_diff = actual_baudrate - baudrate;
    } else {
        baudrate_diff = baudrate - actual_baudrate;
    }
    if (20 * baudrate_diff > actual_baudrate) {
        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("set baudrate %d is not within 5%% of desired value"), actual_baudrate);
    }
	// 串口初始化完成
	HAL_UART_Receive_IT(&self->huart, self->rcache, 0);  // 调用一次即可, 以后都从队列里拿数据
    self->is_enabled = true;

    return mp_const_none;
}

/// \classmethod \constructor(bus, ...)
///
/// Construct a UART object on the given bus.  `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'.
/// With no additional parameters, the UART object is created but not
/// initialised (it has the settings from the last initialisation of
/// the bus, if any).  If extra arguments are given, the bus is initialised.
/// See `init` for parameters of initialisation.
///
/// The physical pins of the UART buses are:
///
///   - `UART(4)` is on `XA`: `(TX, RX) = (X1, X2) = (PA0, PA1)`
///   - `UART(1)` is on `XB`: `(TX, RX) = (X9, X10) = (PB6, PB7)`
///   - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)`
///   - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)`
///   - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)`
STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    // check arguments
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

	int uart_id = mp_obj_get_int(args[0]);
	if (!_is_uart_exists(uart_id)) {
		mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) doesn't exist"), uart_id);
    }

    // check if the UART is reserved for system use or not
    if (MICROPY_HW_UART_REPL == uart_id) {
         mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) is reserved"), uart_id);
    }
	
    pyb_uart_obj_t *self;
    if (MP_STATE_PORT(pyb_uart_obj_all)[uart_id] == NULL) {
        // create new UART object		
        self = m_new0(pyb_uart_obj_t, 1);
        self->base.type = &pyb_uart_type;
        self->uart_id = uart_id;
        MP_STATE_PORT(pyb_uart_obj_all)[uart_id] = self;
    } else {
        // reference existing UART object
        self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id];
    }
    if (n_args > 1 || n_kw > 0) {
        // start the peripheral
        mp_map_t kw_args;
        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
        pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
    }

    return MP_OBJ_FROM_PTR(self);
}

STATIC mp_obj_t pyb_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
    return pyb_uart_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);

/// \method deinit()
/// Turn off the UART bus.
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
	HAL_UART_DeInit(&self->huart);
	self->is_enabled = false;
    self->fifo.front = 0;
    self->fifo.rear = 0;
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);

/// \method any()
/// Return `True` if any characters waiting, else `False`.
STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
	return MP_OBJ_NEW_SMALL_INT( (!fifo_empty(&self->fifo)) ? (1) : (0)); /* 获取RX FIFO的字节数 */
    //return MP_OBJ_NEW_SMALL_INT(uart_rx_any(self));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);


/// \method writechar(char)
/// Write a single character on the bus.  `char` is an integer to write.
/// Return value: `None`.
STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
    // get the character to write (might be 9 bits)
    uint16_t data = mp_obj_get_int(char_in);
    
    // 检查串口是否初始化
    uart_init_detect(self, "Uart(%d) writchar error, please init", self->uart_id);
    
	if(HAL_UART_Transmit(&self->huart, (uint8_t*)&data, 1, self->timeout) != HAL_OK){
		mp_raise_OSError(MP_ETIMEDOUT);
	}
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar);

/// \method readchar()
/// Receive a single character on the bus.
/// Return value: The character read, as an integer.  Returns -1 on timeout.
STATIC mp_obj_t pyb_uart_readchar(mp_obj_t self_in) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
	uint8_t data;
    
    // 检查串口是否初始化
    uart_init_detect(self, "Uart(%d) readchar error, please init", self->uart_id);
    // 无数据返回-1, 因为-1(0xFF)不是有效的ascii字符
    if(!fifo_pop(&self->fifo, &data)){
        data = -1;
    }
    return MP_OBJ_NEW_SMALL_INT(data);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);
 
// uart.sendbreak()
STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
	self->huart.Instance->LC |= UART_LC_SBE;
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);

#if 0
// 还要在irq handler里添加, 本版本不移植uart相关的IRQ
// Check the flags to see if the user handler should be called
// if (self->mp_irq_trigger & self->mp_irq_flags) {
//     mp_irq_handler(self->mp_irq_obj);
// }
	
// irq(handler, trigger, hard)
STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS];
    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_IRQ_ARG_INIT_NUM_ARGS, mp_irq_init_args, args);
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);

    if (self->mp_irq_obj == NULL) {
        self->mp_irq_trigger = 0;
        self->mp_irq_obj = mp_irq_new(&uart_irq_methods, MP_OBJ_FROM_PTR(self));
    }

    if (n_args > 1 || kw_args->used != 0) {
        // Check the handler
        mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj;
        if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
            mp_raise_ValueError(MP_ERROR_TEXT("handler must be None or callable"));
        }

        // Check the trigger
        mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
        mp_uint_t not_supported = trigger & ~MP_UART_ALLOWED_FLAGS;
        if (trigger != 0 && not_supported) {
            mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%08x unsupported"), not_supported);
        }

        // Reconfigure user IRQs
        uart_irq_config(self, false);
        self->mp_irq_obj->handler = handler;
        self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
        self->mp_irq_trigger = trigger;
        uart_irq_config(self, true);
    }

    return MP_OBJ_FROM_PTR(self->mp_irq_obj);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq);

#endif

STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
    // instance methods

    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) },
    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_uart_deinit_obj) },
    { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_uart_any_obj) },

    /// \method read([nbytes])
    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },  // stream系列函数由py/stream.c文件提供
    /// \method readline()
    { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
    /// \method readinto(buf[, nbytes])
    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
    /// \method write(buf)
    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
    //{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_uart_irq_obj) },

    { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&pyb_uart_writechar_obj) },
    { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&pyb_uart_readchar_obj) },
    { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&pyb_uart_sendbreak_obj) },

    // class constants
    { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS_CTS) },

    // IRQ flags
    //{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_FLAG_IDLE) },
};

STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);

STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
    byte *buf = buf_in;
    
    uart_init_detect(self, "Uart(%d) read error, please init", self->uart_id);
    
    // make sure we want at least 1 char
    if (size == 0) {
        return 0;
    }
    // 从FIFO里拷贝数据
    uint32_t cnt = 0;
    uint32_t tickstart = HAL_GetTick();
    //printf("pyb_uart_read before out queue, que_addr:%p, front:%d, rear:%d.\n", &self->fifo, self->fifo.front, self->fifo.rear);
    while(1){
        // 出队列
        while(fifo_pop(&self->fifo, buf + cnt) && cnt < size) cnt++;
        // 判断是否接收满或超时
        if(cnt >= size || HAL_GetTick() - tickstart >= self->timeout){
#if 0
            if(cnt > 0){
                *errcode = 0;
                return cnt;
            }else{
                *errcode = MP_EAGAIN;
                return MP_STREAM_ERROR;
            }
#else
            return cnt;  // 超时无数据触发异常(MP_STREAM_ERROR), 为了简化使用, 无数据时候直接返回0即可, 上层收到b''
#endif
        }
        MICROPY_EVENT_POLL_HOOK   // 事件调度(执行中断回调)
        HAL_Delay(5);
    }
}


#if 0
int _wait_for_tx_finsihed(pyb_uart_obj_t* self)
{
    uint32_t tickstart = HAL_GetTick();
    while(1){
        if(!self->huart.TxXferCount)
            break;
        if(!self->timeout || HAL_GetTick() - tickstart > self->timeout)
            return -1; 
    }
    return 0;
}
#endif

STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
    
    uart_init_detect(self, "Uart(%d) write error, please init", self->uart_id);
    
    // 忙等发送过程
    if(HAL_UART_Transmit(&self->huart, (uint8_t*)buf_in, size, HAL_MAX_DELAY) == HAL_OK){
	    return size;	
	}
    //if(HAL_UART_Transmit_IT(&self->huart, (uint8_t*)buf_in, size) == HAL_OK){
    //    return _wait_for_tx_finsihed(self) ? (MP_ETIMEDOUT) : (size);
    //}
	*errcode = MP_EAGAIN;
	return MP_STREAM_ERROR;
}

STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
    pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
    mp_uint_t ret;
    if (request == MP_STREAM_POLL) {
        uintptr_t flags = arg;
        ret = 0;
        if ((flags & MP_STREAM_POLL_RD) && (!fifo_empty(&self->fifo))){  // 接收FIFO里有数据
            ret |= MP_STREAM_POLL_RD;
        }
        if ((flags & MP_STREAM_POLL_WR) && (self->huart.Instance->FIFOS & UART_FIFOS_TFC) < UART_FIFO_FULL){ // 接收FIFO有空余位置
            ret |= MP_STREAM_POLL_WR;
        }
    } else {
        *errcode = MP_EINVAL;
        ret = MP_STREAM_ERROR;
    }
    return ret;
}


STATIC const mp_stream_p_t uart_stream_p = {
    .read = pyb_uart_read,
    .write = pyb_uart_write,
    .ioctl = pyb_uart_ioctl,
    .is_text = false,
};

const mp_obj_type_t pyb_uart_type = {
    { &mp_type_type },
    .name = MP_QSTR_UART,
    .print = pyb_uart_print,
    .make_new = pyb_uart_make_new,
    .getiter = mp_identity_getiter,
    .iternext = mp_stream_unbuffered_iter,
    .protocol = &uart_stream_p,
    .locals_dict = (mp_obj_dict_t *)&pyb_uart_locals_dict,
};

